---
title: 套件管理與生態系統
description: 對比 Python 和 JavaScript 套件管理系統，理解 npm/yarn 與 pip 的差異，掌握 JavaScript 生態系統導航技巧
---

# 模組 09：套件管理與生態系統

## 學習目標

完成本模組後，你將能夠：
- 理解 pip 和 npm/yarn 之間的差異
- 掌握 JavaScript 專案中的相依性管理
- 對比虛擬環境與 node_modules
- 導航 JavaScript 套件生態系統
- 實施相依性管理的安全最佳實務

## 套件管理器：pip vs npm/yarn

### Python：pip 和虛擬環境

在 Python 中，你熟悉的方式：

<PythonEditor title="Python 套件管理" compare={true}>
```python !! py
# requirements.txt
requests==2.28.1
django==4.1.0
pytest==7.1.0

# 安裝套件
# pip install -r requirements.txt

# 虛擬環境
# python -m venv venv
# source venv/bin/activate (Linux/Mac)
# venv\Scripts\activate (Windows)

import requests
import django
from django.http import JsonResponse

def fetch_data():
    response = requests.get('https://api.example.com/data')
    return response.json()
```

```javascript !! js
// package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "dependencies": {
    "axios": "^1.1.0",
    "express": "^4.18.0"
  },
  "devDependencies": {
    "jest": "^29.0.0"
  }
}

// 安裝套件
// npm install 或 yarn install

// 無需虛擬環境 - 使用 node_modules/
const axios = require('axios');
const express = require('express');

async function fetchData() {
    const response = await axios.get('https://api.example.com/data');
    return response.data;
}
```
</PythonEditor>

### 主要差異

| 方面 | Python (pip) | JavaScript (npm/yarn) |
|------|-------------|----------------------|
| **設定檔** | requirements.txt | package.json |
| **鎖定檔** | 無（pip-tools 有 Pipfile.lock） | package-lock.json / yarn.lock |
| **安裝方式** | 預設全域 | 預設本地（node_modules） |
| **虛擬環境** | 手動（venv, virtualenv） | 自動（node_modules） |
| **版本格式** | `==2.28.1`（精確版本） | `^1.1.0`（語意化版本範圍） |

## 相依性管理

### 語意化版本控制（SemVer）

<PythonEditor title="版本管理" compare={true}>
```python !! py
# Python：生產環境通常使用精確版本
# requirements.txt
django==4.1.0      # 精確版本
requests>=2.28.0   # 最小版本
numpy~=1.21.0      # 相容版本

# pip freeze > requirements.txt
# 建立精確版本以確保可重現性

# 開發環境可能使用：
# django>=4.1.0,<5.0.0
```

```javascript !! js
// JavaScript：預設使用語意化版本控制
// package.json
{
  "dependencies": {
    "express": "^4.18.0",    // ^4.18.0 到 <5.0.0
    "lodash": "~4.17.21",    // ~4.17.21 到 <4.18.0
    "react": "18.2.0"        // 精確版本
  }
}

// package-lock.json 自動鎖定精確版本
// yarn.lock 為 yarn 做同樣的事情

// 版本範圍：
// ^1.2.3 := >=1.2.3 <2.0.0 (相容版本)
// ~1.2.3 := >=1.2.3 <1.3.0 (相近版本)
// 1.2.3  := 精確 1.2.3
```
</PythonEditor>

### 安裝和管理套件

<PythonEditor title="套件安裝" compare={true}>
```python !! py
# Python 套件安裝
# pip install requests
# pip install django==4.1.0
# pip install -e .  # 開發安裝
# pip uninstall requests
# pip list
# pip show requests
# pip check  # 檢查衝突

# 建立 requirements.txt
# pip freeze > requirements.txt

# 從 requirements.txt 安裝
# pip install -r requirements.txt

# 升級套件
# pip install --upgrade requests
# pip list --outdated
```

```javascript !! js
// npm 指令
// npm install express
// npm install express@4.18.0  # 特定版本
// npm install -g nodemon      # 全域安裝
// npm uninstall express
// npm list
// npm info express
// npm audit                   # 安全稽核

// yarn 指令（替代方案）
// yarn add express
// yarn add express@4.18.0
// yarn global add nodemon
// yarn remove express
// yarn list
// yarn info express
// yarn audit

// package.json 中的套件腳本
{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "jest",
    "build": "webpack"
  }
}

// 執行腳本：npm run dev 或 yarn dev
```
</PythonEditor>

## 專案結構與設定

### Python vs JavaScript 專案結構

<PythonEditor title="專案結構" compare={true}>
```python !! py
# Python 專案結構
my_python_project/
├── venv/                 # 虛擬環境
├── src/
│   └── my_package/
│       ├── __init__.py
│       └── main.py
├── tests/
│   └── test_main.py
├── requirements.txt      # 相依性
├── setup.py             # 套件中繼資料
├── README.md
└── .gitignore

# Python 的 .gitignore
__pycache__/
*.pyc
venv/
.env
dist/
build/
*.egg-info/
```

```javascript !! js
// JavaScript 專案結構
my_js_project/
├── node_modules/        # 相依性（自動產生）
├── src/
│   └── index.js
├── tests/
│   └── index.test.js
├── package.json         # 專案中繼資料和相依性
├── package-lock.json    # 鎖定檔（自動產生）
├── README.md
└── .gitignore

// JavaScript 的 .gitignore
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env
dist/
build/
coverage/

// package.json 結構
{
  "name": "my-js-project",
  "version": "1.0.0",
  "description": "我的出色專案",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "jest"
  },
  "dependencies": {},
  "devDependencies": {},
  "engines": {
    "node": ">=16.0.0"
  }
}
```
</PythonEditor>

## 套件生態系統

### 發現和評估套件

<PythonEditor title="套件發現" compare={true}>
```python !! py
# Python：PyPI（Python 套件索引）
# https://pypi.org/

# 熱門的 Python 套件：
import requests     # HTTP 函式庫
import django      # Web 框架
import flask       # 輕量級 Web 框架
import numpy       # 數值計算
import pandas      # 資料處理
import pytest      # 測試框架
import click       # CLI 框架
import sqlalchemy  # ORM

# 評估套件：
# - PyPI 下載量和星數
# - GitHub 活躍度
# - 文件品質
# - 社群支援
```

```javascript !! js
// JavaScript：npm 註冊表
// https://www.npmjs.com/

// 熱門的 JavaScript 套件：
const express = require('express');      // Web 框架
const lodash = require('lodash');        // 工具函式庫
const axios = require('axios');          // HTTP 用戶端
const moment = require('moment');        // 日期函式庫
const validator = require('validator');  // 驗證
const mongoose = require('mongoose');    // MongoDB ODM
const jest = require('jest');           // 測試框架
const commander = require('commander');  // CLI 框架

// 評估套件：
// - npm 週下載量
// - GitHub 星數和活躍度
// - npm audit 安全檢查
// - 打包大小影響
// - TypeScript 支援
// - 維護狀態

// 有用的評估指令：
// npm info package-name
// npm audit
// npx bundle-phobia package-name  # 打包大小
```
</PythonEditor>

### 安全和最佳實務

<PythonEditor title="安全最佳實務" compare={true}>
```python !! py
# Python 安全實務
# pip check  # 檢查相依性衝突
# pip-audit  # 安全漏洞掃描器
# safety check  # 另一個安全掃描器

# 保持相依性更新
# pip list --outdated
# pip install --upgrade package-name

# 生產環境使用精確版本
# requirements.txt 應該有精確版本
django==4.1.0
requests==2.28.1

# 使用虛擬環境進行隔離
# python -m venv venv
# source venv/bin/activate

# 環境變數使用範例
import os
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.getenv('API_KEY')
```

```javascript !! js
// JavaScript 安全實務
// npm audit  # 檢查漏洞
// npm audit fix  # 自動修復漏洞
// yarn audit  # Yarn 等價指令

// 保持相依性更新
// npm outdated
// npm update package-name
// npx npm-check-updates  # 檢查主版本更新

// 使用鎖定檔確保可重現建置
// package-lock.json (npm)
// yarn.lock (yarn)

// 環境變數
require('dotenv').config();
const API_KEY = process.env.API_KEY;

// 安全工具
// npm install --save-dev eslint-plugin-security
// npx snyk test  # Snyk 安全測試

// package.json 安全設定
{
  "scripts": {
    "audit": "npm audit",
    "audit-fix": "npm audit fix",
    "security-check": "npx snyk test"
  },
  "engines": {
    "node": ">=16.0.0",
    "npm": ">=8.0.0"
  }
}
```
</PythonEditor>

## 進階套件管理

### Monorepo 和工作區

<PythonEditor title="Monorepo 管理" compare={true}>
```python !! py
# Python：原生 monorepo 支援有限
# 通常使用工具如：
# - pants（由 Twitter 開發）
# - bazel
# - poetry with workspace plugin

# 多套件專案結構
my_monorepo/
├── packages/
│   ├── package_a/
│   │   ├── setup.py
│   │   └── requirements.txt
│   └── package_b/
│       ├── setup.py
│       └── requirements.txt
├── shared_requirements.txt
└── setup.py

# 手動相依性管理
# 每個套件都有自己的 requirements.txt
# 共享相依性在根目錄 requirements.txt
```

```javascript !! js
// JavaScript：原生工作區支援

// package.json（根目錄）
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "devDependencies": {
    "lerna": "^5.0.0"
  }
}

// packages/package-a/package.json
{
  "name": "@myorg/package-a",
  "version": "1.0.0",
  "dependencies": {
    "@myorg/package-b": "1.0.0",
    "lodash": "^4.17.21"
  }
}

// 工作區指令
// npm install  # 安裝所有工作區相依性
// npm run test --workspaces  # 在所有套件中執行測試
// npm run build --workspace=@myorg/package-a

// Lerna 用於進階 monorepo 管理
// npx lerna bootstrap  # 安裝相依性
// npx lerna run test   # 跨套件執行指令
// npx lerna publish    # 發布套件
```
</PythonEditor>

### 發布套件

<PythonEditor title="套件發布" compare={true}>
```python !! py
# Python：發布到 PyPI
# setup.py
from setuptools import setup, find_packages

setup(
    name="my-awesome-package",
    version="1.0.0",
    description="一個出色的 Python 套件",
    author="你的名字",
    author_email="your.email@example.com",
    packages=find_packages(),
    install_requires=[
        "requests>=2.28.0",
        "click>=8.0.0"
    ],
    python_requires=">=3.8",
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
)

# 發布步驟：
# python setup.py sdist bdist_wheel
# twine upload dist/*
```

```javascript !! js
// JavaScript：發布到 npm

// package.json
{
  "name": "my-awesome-package",
  "version": "1.0.0",
  "description": "一個出色的 JavaScript 套件",
  "main": "lib/index.js",
  "module": "es/index.js",
  "types": "lib/index.d.ts",
  "author": "你的名字 <your.email@example.com>",
  "license": "MIT",
  "keywords": ["javascript", "utility"],
  "repository": {
    "type": "git",
    "url": "https://github.com/yourname/my-awesome-package"
  },
  "files": [
    "lib/",
    "es/",
    "README.md"
  ],
  "scripts": {
    "build": "rollup -c",
    "prepublishOnly": "npm run build"
  },
  "peerDependencies": {
    "react": ">=16.8.0"
  },
  "engines": {
    "node": ">=14.0.0"
  }
}

// 發布步驟：
// npm login
// npm publish
// npm version patch  # 版本升級
// npm publish

// 作用域套件（推薦用於組織）
// @myorg/my-package
```
</PythonEditor>

## 實戰練習

### 練習 1：套件遷移

將 Python 專案結構轉換為 JavaScript：

<PythonEditor title="練習：專案遷移">
```python !! py
# 給定這個 Python 專案結構：
my_api/
├── venv/
├── src/
│   ├── __init__.py
│   ├── api.py
│   └── utils.py
├── tests/
│   └── test_api.py
├── requirements.txt
└── setup.py

# requirements.txt 內容：
flask==2.2.0
requests==2.28.1
pytest==7.1.0
python-dotenv==0.19.0

# 任務：建立等價的 JavaScript 專案結構
# 包含適當的 package.json 和相依性
```

```javascript !! js
// 解決方案：JavaScript 專案結構
my_api/
├── node_modules/        # 自動產生
├── src/
│   ├── api.js
│   └── utils.js
├── tests/
│   └── api.test.js
├── package.json
├── package-lock.json    # 自動產生
└── .env

// package.json 解決方案：
{
  "name": "my-api",
  "version": "1.0.0",
  "description": "我的 API 專案",
  "main": "src/api.js",
  "scripts": {
    "start": "node src/api.js",
    "dev": "nodemon src/api.js",
    "test": "jest",
    "test:watch": "jest --watch"
  },
  "dependencies": {
    "express": "^4.18.0",
    "axios": "^1.1.0",
    "dotenv": "^16.0.0"
  },
  "devDependencies": {
    "jest": "^29.0.0",
    "nodemon": "^2.0.0"
  },
  "engines": {
    "node": ">=16.0.0"
  }
}
```
</PythonEditor>

### 練習 2：相依性稽核

<PythonEditor title="練習：安全稽核">
```python !! py
# Python 安全檢查
# pip install safety
# safety check
# pip-audit

# 範例漏洞相依性檢查
import requests
import flask
import sqlalchemy

# 檢查已知漏洞：
# 1. 執行安全掃描器
# 2. 更新有漏洞的套件
# 3. 查看安全公告
```

```javascript !! js
// JavaScript 安全稽核
// npm audit
// yarn audit

// 有潛在問題的範例 package.json
{
  "dependencies": {
    "lodash": "4.17.20",      // 可能存在漏洞
    "express": "4.17.0",      // 過時版本
    "axios": "0.21.0"         // 已知漏洞
  }
}

// 修復漏洞：
// npm audit fix
// npm update lodash
// npm install lodash@latest

// 自動化安全檢查：
{
  "scripts": {
    "security-check": "npm audit && npx snyk test",
    "update-deps": "npx npm-check-updates -u && npm install"
  }
}
```
</PythonEditor>

## 最佳實務總結

### 套件管理最佳實務

1. **使用鎖定檔**確保可重現建置
2. **定期安全稽核**使用 `npm audit`
3. **保持相依性更新**但要充分測試
4. **生產環境使用精確版本**
5. **最小化相依性**- 避免不必要的套件
6. **新增相依性前檢查套件品質**

### 生態系統導航技巧

1. **檢查套件熱門度**和維護狀態
2. **閱讀文件**和範例
3. **檢查 TypeScript 支援**（如果使用 TypeScript）
4. **考慮打包大小**（前端套件）
5. **評估替代方案**後再選擇套件
6. **使用已建立的、維護良好的套件**

## 下一步

在下一個模組中，我們將探索測試框架和除錯技術，對比 Python 的 unittest/pytest 與 JavaScript 的 Jest 和其他測試工具。

我們將涵蓋的關鍵主題：
- Jest vs pytest 對比
- 單元測試模式
- 模擬和存根
- 整合測試
- 除錯工具和技術

---

*繼續學習 [模組 10：測試框架與除錯技巧 →](/docs/py2js/module-10-testing-debugging)*
